﻿using System.Windows.Controls;

namespace DimensionsHelper.Client.Navigation;

public class NavigatingEventArgs(Type pageType) : EventArgs
{
    public Type? PageType { get; set; } = pageType;
}


public class NavigationService(IServiceProvider serviceProvider)
{
    private readonly Stack<Type> _future = [];
    private readonly Stack<Type> _history = [];
    
    private Type? _currentPage;
    private Frame? _frame;

    public event EventHandler<NavigatingEventArgs>? Navigating;


    public void RaiseNavigatingEvent(Type type)
    {
        Navigating?.Invoke(this, new NavigatingEventArgs(type));
    }


    public bool IsBackHistoryNonEmpty()
    {
        return _history.TryPeek(out _);
    }


    public void SetFrame(Frame frame)
    {
        _frame = frame;
    }


    public void NavigateTo(Type? pageType)
    {
        if (pageType == null)
        {
            return;
        }

        _future.Clear();
        RaiseNavigatingEvent(pageType);
    }


    public void Navigate(Type? type, Type? modelType, string? scopeKey)
    {
        if (type == null || _frame == null)
        {
            return;
        }

        if (_currentPage != null)
        {
            _history.Push(_currentPage);
        }

        _currentPage = type;

        object page = string.IsNullOrEmpty(scopeKey)
            ? serviceProvider.GetRequiredService(type)
            : serviceProvider.GetRequiredKeyedService(type, scopeKey);

        if (modelType != null && page is Page pageControl)
        {
            object? data = !string.IsNullOrEmpty(scopeKey)
                ? serviceProvider.GetKeyedServices(modelType, scopeKey).FirstOrDefault()
                : serviceProvider.GetService(modelType);

            if (data != null)
            {
                pageControl.DataContext = data;
            }
        }

        _frame.Navigate(page);
    }


    public void NavigateBack()
    {
        if (!_history.TryPop(out Type? top))
        {
            return;
        }

        _future.Push(top);
        RaiseNavigatingEvent(top);
    }


    public void NavigateForward()
    {
        if (!_future.TryPop(out Type? top))
        {
            return;
        }

        _history.Push(top);
        RaiseNavigatingEvent(top);
    }
}